package serial

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"strings"
	"sync"
	"time"

	"gitee.com/rw555/fdsmastergo/pkg/logger"
	"github.com/tarm/serial"
	"go.uber.org/zap"
)

// ConnectionState 连接状态
type ConnectionState int

const (
	StateDisconnected ConnectionState = iota // 未连接
	StateConnecting                          // 连接中
	StateConnected                           // 已连接
	StateReconnecting                        // 重连中
	StateError                               // 错误状态
)

// String 返回连接状态的字符串表示
func (s ConnectionState) String() string {
	switch s {
	case StateDisconnected:
		return "未连接"
	case StateConnecting:
		return "连接中"
	case StateConnected:
		return "已连接"
	case StateReconnecting:
		return "重连中"
	case StateError:
		return "错误状态"
	default:
		return "未知状态"
	}
}

// Driver 串口设备驱动
type Driver struct {
	config *Config
	port   io.ReadWriteCloser
	state  ConnectionState
	mutex  sync.RWMutex

	// 通信相关
	reader       *bufio.Reader
	writer       *bufio.Writer
	readChan     chan string      // 读取数据通道
	responseChan chan string      // 响应数据通道
	eventChan    chan *Event      // 事件数据通道
	errorChan    chan error       // 错误通道
	stopChan     chan struct{}    // 停止信号
	cmdChan      chan *cmdRequest // 命令请求通道

	// 重连相关
	reconnectCount int
	lastError      error

	// 回调函数
	onStateChanged  func(state ConnectionState)
	onEventReceived func(event *Event)
	onError         func(error)

	// 上下文
	ctx    context.Context
	cancel context.CancelFunc
	wg     sync.WaitGroup
}

// cmdRequest 命令请求
type cmdRequest struct {
	command    *Command
	responseCh chan *cmdResponse
	timeout    time.Duration
}

// cmdResponse 命令响应
type cmdResponse struct {
	response *Response
	error    error
}

// NewDriver 创建新的串口驱动
func NewDriver(config *Config) (*Driver, error) {
	if err := config.Validate(); err != nil {
		return nil, fmt.Errorf("配置验证失败: %w", err)
	}

	ctx, cancel := context.WithCancel(context.Background())

	d := &Driver{
		config:       config,
		state:        StateDisconnected,
		readChan:     make(chan string, 8), // 原始数据入口，需要大缓冲
		responseChan: make(chan string, 4), // 命令响应，需要足够缓冲处理并发命令
		eventChan:    make(chan *Event, 2), // 实时事件，时效性强，适中缓冲
		errorChan:    make(chan error, 4),  // 错误信息，低频，小缓冲
		stopChan:     make(chan struct{}),
		cmdChan:      make(chan *cmdRequest, 4), // 命令请求，低频，小缓冲
		ctx:          ctx,
		cancel:       cancel,
	}

	return d, nil
}

// SetStateChangedCallback 设置状态变化回调
func (d *Driver) SetStateChangedCallback(callback func(state ConnectionState)) {
	d.onStateChanged = callback
}

// SetEventReceivedCallback 设置事件接收回调
func (d *Driver) SetEventReceivedCallback(callback func(event *Event)) {
	d.onEventReceived = callback
}

// GetEventChannel 获取事件通道（用于统一的通道模式处理）
func (d *Driver) GetEventChannel() <-chan *Event {
	return d.eventChan
}

// SetErrorCallback 设置错误回调
func (d *Driver) SetErrorCallback(callback func(error)) {
	d.onError = callback
}

// Connect 连接串口设备
func (d *Driver) Connect() error {
	d.mutex.Lock()
	defer d.mutex.Unlock()

	if d.state == StateConnected {
		logger.SystemInfo("设备已连接，跳过连接操作")
		return nil
	}
	d.setState(StateConnecting)

	// 配置串口参数
	serialConfig := &serial.Config{
		Name:        d.config.Port,
		Baud:        d.config.BaudRate,
		ReadTimeout: d.config.ReadTimeout,
		Size:        byte(d.config.DataBits),
	}

	logger.SystemInfo("🔧 配置串口参数",
		zap.String("port", serialConfig.Name),
		zap.Int("baud", serialConfig.Baud),
		zap.Duration("read_timeout", serialConfig.ReadTimeout),
		zap.Uint8("data_bits", uint8(serialConfig.Size)))

	// 设置停止位
	switch d.config.StopBits {
	case 1:
		serialConfig.StopBits = serial.Stop1
	case 2:
		serialConfig.StopBits = serial.Stop2
	default:
		return fmt.Errorf("不支持的停止位: %d", d.config.StopBits)
	}

	// 设置校验位
	switch d.config.Parity {
	case "N":
		serialConfig.Parity = serial.ParityNone
	case "E":
		serialConfig.Parity = serial.ParityEven
	case "O":
		serialConfig.Parity = serial.ParityOdd
	default:
		return fmt.Errorf("不支持的校验位: %s", d.config.Parity)
	}

	// 打开串口
	port, err := serial.OpenPort(serialConfig)
	if err != nil {
		d.setState(StateError)
		d.lastError = err
		return fmt.Errorf("打开串口失败: %w", err)
	}

	d.port = port
	d.reader = bufio.NewReaderSize(port, d.config.ReadBufferSize)
	d.writer = bufio.NewWriterSize(port, d.config.WriteBufferSize)
	d.setState(StateConnected)
	d.lastError = nil
	d.reconnectCount = 0

	// 清空串口缓冲区中的历史数据
	if err := d.flushBuffers(); err != nil {
		logger.SystemWarn("清空缓冲区失败", zap.Error(err))
	}

	// 启动数据处理协程
	d.wg.Add(3)
	go d.readLoop()
	go d.processLoop()
	go d.commandLoop()

	return nil
}

// flushBuffers 清空串口缓冲区中的历史数据
func (d *Driver) flushBuffers() error {
	logger.SystemInfo("🧹 清空串口缓冲区历史数据...")

	// 临时设置短超时，避免长时间等待
	originalTimeout := d.config.ReadTimeout
	d.config.ReadTimeout = 100 * time.Millisecond
	defer func() {
		d.config.ReadTimeout = originalTimeout
	}()

	buf := make([]byte, 1024)
	totalFlushed := 0

	// 第一阶段：快速清空现有数据（带超时）
	startTime := time.Now()
	for i := 0; i < 10; i++ {
		// 检查是否超时（最多等待1秒）
		if time.Since(startTime) > 1*time.Second {
			logger.SystemWarn("缓冲区清理超时，停止清理")
			break
		}

		n, _ := d.port.Read(buf)
		if n > 0 {
			totalFlushed += n
			logger.SystemDebug("丢弃历史数据",
				zap.Int("round", i+1),
				zap.Int("bytes", n),
				zap.String("preview", string(buf[:min(n, 30)])))
		} else {
			// 没有数据就等待一小段时间
			time.Sleep(50 * time.Millisecond)
		}
	}

	// 第二阶段：短暂等待下位机稳定（减少等待时间）
	/*if totalFlushed > 0 {
		logger.SystemInfo("⏳ 等待下位机稳定...")
		time.Sleep(200 * time.Millisecond) // 减少到200ms

		// 第三阶段：再次清理可能新产生的数据（带超时）
		cleanupStart := time.Now()
		for i := 0; i < 5; i++ {
			if time.Since(cleanupStart) > 1*time.Second {
				logger.SystemWarn("延迟清理超时，停止清理")
				break
			}

			n, _ := d.port.Read(buf)
			if n > 0 {
				totalFlushed += n
				logger.SystemDebug("清理延迟数据",
					zap.Int("bytes", n),
					zap.String("preview", string(buf[:min(n, 30)])))
			} else {
				break
			}
		}
	}*/

	if totalFlushed > 0 {
		logger.SystemInfo("✅ 已清空缓冲区历史数据",
			zap.Int("total_bytes", totalFlushed))
	} else {
		logger.SystemDebug("缓冲区无历史数据")
	}

	return nil
}

// min helper function
func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

// sendWithDropOldest 非阻塞发送，通道满时丢弃最早的数据
func sendWithDropOldest(ch chan string, data string, channelName string) {
	select {
	case ch <- data:
		// 成功发送
	default:
		// 通道满，丢弃最早的数据
		select {
		case <-ch: // 丢弃一个最早的数据
			select {
			case ch <- data: // 发送新数据
				logger.SystemDebug("通道满，丢弃最早数据后发送新数据",
					zap.String("channel", channelName),
					zap.String("data", data))
			default:
				logger.SystemWarn("通道满且无法发送",
					zap.String("channel", channelName))
			}
		default:
			logger.SystemWarn("通道满且无法丢弃",
				zap.String("channel", channelName))
		}
	}
}

// sendEventWithDropOldest 非阻塞发送事件，通道满时丢弃最早的事件
func sendEventWithDropOldest(ch chan *Event, event *Event, channelName string) {
	select {
	case ch <- event:
		// 成功发送
	default:
		// 通道满，丢弃最早的事件
		select {
		case <-ch: // 丢弃一个最早的事件
			select {
			case ch <- event: // 发送新事件
				logger.SystemDebug("事件通道满，丢弃最早事件后发送新事件",
					zap.String("channel", channelName),
					zap.String("event_type", string(event.Type)))
			default:
				logger.SystemWarn("事件通道满且无法发送",
					zap.String("channel", channelName))
			}
		default:
			logger.SystemWarn("事件通道满且无法丢弃",
				zap.String("channel", channelName))
		}
	}
}

// Disconnect 断开串口连接
func (d *Driver) Disconnect() error {
	d.mutex.Lock()
	defer d.mutex.Unlock()

	if d.state == StateDisconnected {
		return nil
	}

	// 停止所有协程
	d.cancel()
	close(d.stopChan)

	// 等待协程结束
	d.wg.Wait()

	// 关闭串口
	if d.port != nil {
		if err := d.port.Close(); err != nil {
			logger.SystemError("关闭串口失败", zap.Error(err))
		}
		d.port = nil
	}

	d.setState(StateDisconnected)
	logger.SystemInfo("串口设备连接已断开", zap.String("port", d.config.Port))

	return nil
}

// IsConnected 检查是否已连接
func (d *Driver) IsConnected() bool {
	d.mutex.RLock()
	defer d.mutex.RUnlock()
	return d.state == StateConnected
}

// GetState 获取连接状态
func (d *Driver) GetState() ConnectionState {
	d.mutex.RLock()
	defer d.mutex.RUnlock()
	return d.state
}

// GetLastError 获取最后的错误
func (d *Driver) GetLastError() error {
	d.mutex.RLock()
	defer d.mutex.RUnlock()
	return d.lastError
}

// SendCommand 发送命令并等待响应
func (d *Driver) SendCommand(cmd *Command) (*Response, error) {
	return d.SendCommandWithTimeout(cmd, d.config.CommandTimeout)
}

// SendCommandWithTimeout 发送命令并指定超时时间
func (d *Driver) SendCommandWithTimeout(cmd *Command, timeout time.Duration) (*Response, error) {
	if !d.IsConnected() {
		return nil, fmt.Errorf("设备未连接")
	}

	responseCh := make(chan *cmdResponse, 1)
	request := &cmdRequest{
		command:    cmd,
		responseCh: responseCh,
		timeout:    timeout,
	}

	// 发送命令请求
	select {
	case d.cmdChan <- request:
	case <-time.After(timeout):
		return nil, fmt.Errorf("命令发送超时")
	case <-d.ctx.Done():
		return nil, fmt.Errorf("设备已关闭")
	}

	// 等待响应
	select {
	case resp := <-responseCh:
		return resp.response, resp.error
	case <-time.After(timeout):
		return nil, fmt.Errorf("命令响应超时")
	case <-d.ctx.Done():
		return nil, fmt.Errorf("设备已关闭")
	}
}

// setState 设置连接状态
func (d *Driver) setState(state ConnectionState) {
	if d.state != state {
		oldState := d.state
		d.state = state

		if d.config.EnableDebugLog {
			logger.SystemDebug("串口状态变化",
				zap.String("from", oldState.String()),
				zap.String("to", state.String()))
		}

		if d.onStateChanged != nil {
			go d.onStateChanged(state)
		}
	}
}

// readLoop 读取数据循环
func (d *Driver) readLoop() {
	defer d.wg.Done()

	for {
		select {
		case <-d.ctx.Done():
			logger.SystemInfo("收到退出信号，停止读取循环")
			return
		case <-d.stopChan:
			logger.SystemInfo("收到停止信号，停止读取循环")
			return
		default:
			// 设置读取超时
			d.mutex.RLock()
			if d.port == nil {
				d.mutex.RUnlock()
				logger.SystemWarn("串口设备为空，等待重连...")
				time.Sleep(100 * time.Millisecond)
				continue
			}
			d.mutex.RUnlock()

			// 读取一行数据
			logger.SystemDebug("正在等待串口数据...")

			// 读取任何可用数据
			buf := make([]byte, 1024)
			n, err := d.reader.Read(buf)
			if err != nil {
				if err != io.EOF {
					logger.SystemError("串口读取失败", zap.Error(err))
					d.errorChan <- fmt.Errorf("读取数据失败: %w", err)

					// 检测到连接错误，更新状态
					d.mutex.Lock()
					if d.state == StateConnected {
						logger.SystemWarn("检测到连接断开，更新状态")
						d.setState(StateError)
						d.lastError = err
					}
					d.mutex.Unlock()
				} else {
					logger.SystemDebug("读取到EOF，可能是暂时无数据")
				}
				time.Sleep(10 * time.Millisecond) // 避免忙等待
				continue
			}

			if n > 0 {
				data := string(buf[:n])
				logger.SystemDebug("🔍 收到原始数据",
					zap.String("raw_data", fmt.Sprintf("%q", data)),
					zap.Int("length", n))

				// 处理JSON数据的分包/粘包问题
				d.processRawData(data)
			}
		}
	}
}

// processRawData 处理原始数据，分离多个JSON对象
func (d *Driver) processRawData(data string) {
	// 清理数据
	data = strings.TrimSpace(data)
	if data == "" {
		return
	}

	// 分离多个JSON对象
	jsonObjects := d.splitJSONObjects(data)

	for _, jsonStr := range jsonObjects {
		jsonStr = strings.TrimSpace(jsonStr)
		if jsonStr != "" {
			logger.SystemDebug("📦 分离出JSON对象", zap.String("json", jsonStr))
			// 发送到处理通道
			select {
			case d.readChan <- jsonStr:
				logger.SystemDebug("数据已发送到处理通道", zap.String("data", jsonStr))
			case <-d.ctx.Done():
				return
			default:
				logger.SystemWarn("处理通道已满，丢弃数据", zap.String("data", jsonStr))
			}
		}
	}
}

// splitJSONObjects 分离粘在一起的JSON对象
func (d *Driver) splitJSONObjects(data string) []string {
	var results []string
	var current strings.Builder
	braceCount := 0
	inString := false
	escaped := false

	for _, char := range data {
		current.WriteRune(char)

		if escaped {
			escaped = false
			continue
		}

		if char == '\\' && inString {
			escaped = true
			continue
		}

		if char == '"' {
			inString = !inString
			continue
		}

		if !inString {
			if char == '{' {
				braceCount++
			} else if char == '}' {
				braceCount--

				// 当花括号计数回到0时，表示一个完整的JSON对象结束
				if braceCount == 0 {
					jsonStr := strings.TrimSpace(current.String())
					if jsonStr != "" {
						results = append(results, jsonStr)
					}
					current.Reset()
				}
			}
		}
	}

	// 处理剩余数据（可能是不完整的JSON）
	remaining := strings.TrimSpace(current.String())
	if remaining != "" {
		logger.SystemDebug("发现不完整的JSON数据", zap.String("data", remaining))
		// 暂时忽略不完整的数据，实际项目中可能需要缓存等待后续数据
	}

	return results
}

// processLoop 数据处理循环
func (d *Driver) processLoop() {
	defer d.wg.Done()

	for {
		select {
		case <-d.ctx.Done():
			logger.SystemInfo("数据处理循环收到退出信号")
			return
		case <-d.stopChan:
			logger.SystemInfo("数据处理循环收到停止信号")
			return
		case data := <-d.readChan:
			logger.SystemDebug("从读取通道收到数据", zap.String("data", data))
			d.processData(data)
		case err := <-d.errorChan:
			logger.SystemError("从错误通道收到错误", zap.Error(err))
			d.handleError(err)
		}
	}
}

// commandLoop 命令处理循环
func (d *Driver) commandLoop() {
	defer d.wg.Done()

	for {
		select {
		case <-d.ctx.Done():
			logger.SystemInfo("命令处理循环收到退出信号")
			return
		case <-d.stopChan:
			logger.SystemInfo("命令处理循环收到停止信号")
			return
		case request := <-d.cmdChan:
			logger.SystemDebug("从命令通道收到请求",
				zap.String("command_type", string(request.command.C)),
				zap.String("action", string(request.command.A)))
			d.handleCommand(request)
		}
	}
}

// processData 处理接收到的数据
func (d *Driver) processData(data string) {

	// 首先检查是否为响应（命令响应）
	if response, err := ParseResponse(data); err == nil && response.S != "" {
		sendWithDropOldest(d.responseChan, data, "responseChan")
		logger.SystemDebug("响应数据已发送到响应通道")
		return
	}

	// 然后尝试解析为事件（下位机主动上报）
	if event, err := ParseEvent(data); err == nil {

		logger.SystemDebug("🔍 收到的数据是事件", zap.String("data", data))
		if event.Type != "" {
			sendEventWithDropOldest(d.eventChan, event, "eventChan")
			logger.SystemDebug("事件数据已发送到事件通道")
			return
		} else {
			logger.SystemDebug("📋 事件类型为空，跳过")
		}
	} else {
		logger.SystemDebug("📋 事件解析失败", zap.Error(err))
	}

	// 无法解析的数据
	logger.SystemWarn("❌ 收到无法解析的数据",
		zap.String("data", data),
		zap.Int("length", len(data)))
}

// handleCommand 处理命令
func (d *Driver) handleCommand(request *cmdRequest) {
	// 序列化命令
	cmdJSON, err := request.command.ToJSON()
	if err != nil {
		logger.SystemError("命令序列化失败", zap.Error(err))
		request.responseCh <- &cmdResponse{
			error: fmt.Errorf("命令序列化失败: %w", err),
		}
		return
	}

	// 发送命令
	if err := d.writeData(cmdJSON); err != nil {
		logger.SystemError("发送命令失败", zap.Error(err))
		request.responseCh <- &cmdResponse{
			error: fmt.Errorf("发送命令失败: %w", err),
		}
		return
	}

	// 等待响应
	timeout := time.NewTimer(request.timeout)
	defer timeout.Stop()

	logger.SystemDebug("等待命令响应",
		zap.Duration("timeout", request.timeout),
		zap.String("command_type", string(request.command.C)))

	for {
		select {
		case <-timeout.C:
			logger.SystemError("⏰ 命令响应超时",
				zap.String("command", cmdJSON),
				zap.Duration("timeout", request.timeout))
			request.responseCh <- &cmdResponse{
				error: fmt.Errorf("命令响应超时"),
			}
			return
		case data := <-d.responseChan:
			logger.SystemDebug("📥 命令等待循环收到响应数据", zap.String("data", data))
			if response, err := ParseResponse(data); err == nil && response.S != "" {
				request.responseCh <- &cmdResponse{
					response: response,
				}
				return
			} else {
				logger.SystemError("响应数据解析失败",
					zap.String("data", data),
					zap.Error(err))
			}
		case <-d.ctx.Done():
			logger.SystemWarn("设备已关闭，停止等待响应")
			request.responseCh <- &cmdResponse{
				error: fmt.Errorf("设备已关闭"),
			}
			return
		}
	}
}

// writeData 写入数据
func (d *Driver) writeData(data string) error {
	d.mutex.Lock()
	defer d.mutex.Unlock()

	if d.writer == nil {
		return fmt.Errorf("设备未连接")
	}

	// 添加换行符
	data += "\n"

	if _, err := d.writer.WriteString(data); err != nil {
		return fmt.Errorf("写入数据失败: %w", err)
	}

	if err := d.writer.Flush(); err != nil {
		logger.SystemError("刷新缓冲区失败", zap.Error(err))
		return fmt.Errorf("刷新缓冲区失败: %w", err)
	}

	return nil
}

// handleError 处理错误
func (d *Driver) handleError(err error) {
	d.mutex.Lock()
	d.lastError = err
	d.mutex.Unlock()

	logger.SystemError("串口设备错误", zap.Error(err))

	if d.onError != nil {
		go d.onError(err)
	}

	// 如果是连接错误，尝试重连
	if d.state == StateConnected {
		go d.tryReconnect()
	}
}

// tryReconnect 尝试重连
func (d *Driver) tryReconnect() {
	d.mutex.Lock()
	if d.state == StateReconnecting {
		d.mutex.Unlock()
		return
	}
	d.setState(StateReconnecting)
	d.mutex.Unlock()

	for d.reconnectCount < d.config.MaxReconnectTimes {
		d.reconnectCount++

		logger.SystemInfo("尝试重连串口设备",
			zap.Int("attempt", d.reconnectCount),
			zap.Int("max", d.config.MaxReconnectTimes))

		// 关闭当前连接
		if d.port != nil {
			d.port.Close()
			d.port = nil
		}

		// 等待重连间隔
		time.Sleep(d.config.ReconnectInterval)

		// 尝试重新连接
		if err := d.Connect(); err == nil {
			logger.SystemInfo("串口设备重连成功")
			return
		}
	}

	// 重连失败
	d.setState(StateError)
	logger.SystemError("串口设备重连失败，已达到最大重连次数",
		zap.Int("maxRetries", d.config.MaxReconnectTimes))
}
